package mi.payment.ui.base;

import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
import android.view.Display;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.widget.TextView;

import com.sunmi.scan.Config;
import com.sunmi.scan.Image;
import com.sunmi.scan.ImageScanner;
import com.sunmi.scan.Symbol;
import com.sunmi.scan.SymbolSet;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

import mi.payment.R;
import mi.payment.constants.Params;
import mi.payment.ui.qr.code.FinderView;
import mi.payment.ui.qr.code.ScanConfig;
import mi.payment.utils.SoundUtils;
import mi.payment.utils.UIUtils;
import sunmi.payment.L3.L3BroadcastHelper;
import sunmi.payment.L3.L3ErrorCode;
import sunmi.sunmiui.title.Title;
import sunmi.sunmiui.utils.LogUtil;

/**
 * 扫码基类
 */
public abstract class BaseScanActivity extends ParentActivity implements SurfaceHolder.Callback {

    private Camera mCamera;
    private SurfaceHolder mHolder;
    private ImageScanner mImageScanner; // 声明扫描器

    private Handler mAutoFocusHandler;

    private SoundUtils soundUtils;
    private FinderView mFinderView;
    private AtomicBoolean isRUN = new AtomicBoolean(false);

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 保持屏幕常亮
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_scan_qr_code);
        initData();
        initView();
        init();
    }

    private void init() {
        SurfaceView surfaceView = (SurfaceView) findViewById(R.id.surface_view);
        mFinderView = (FinderView) findViewById(R.id.finder_view);
        mAutoFocusHandler = new Handler();
        mHolder = surfaceView.getHolder();
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        mHolder.addCallback(this);
        // 创建扫描器
        mImageScanner = new ImageScanner();
        mImageScanner.setConfig(0, Config.X_DENSITY, 2);
        mImageScanner.setConfig(0, Config.Y_DENSITY, 2);
    }

    private void initView() {
        Title title;
        title = (Title) findViewById(R.id.scan_title);
        title.setButtonVisibility(false, true, true, true);
        title.setHeadBgColor(getResources().getColor(R.color.colorBar));
        title.setTitleText(getBarTitle());
        title.setMenuClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                onBackPressed();
            }

        }, null, null, null);
        TextView hintTextView, clickText;
        hintTextView = (TextView) findViewById(R.id.scan_amount);
        hintTextView.setText(getScanHintText());
        clickText = (TextView) findViewById(R.id.can_not_scan_click);
        clickText.setText(Html.fromHtml("<u>" + getClickText() + "</u>"));
        clickText.setOnClickListener(getOnClickListener());
    }

    protected abstract String getScanHintText();

    protected abstract String getClickText();

    protected abstract String getBarTitle();

    protected abstract View.OnClickListener getOnClickListener();

    protected abstract void initData();

    @Override
    protected void onResume() {
        super.onResume();
        UIUtils.screenMonopoly(1);
        initBeepSound();
        initScanConfig();
    }

    @Override
    public void onBackPressed() {
        handleL3(L3ErrorCode.ERROR_TRADE_CANCEL);
        super.onBackPressed();
    }

    private void handleL3(L3ErrorCode code) {
        if (Params.sL3Params != null) {
            sendCloseAppBroadcast();
            L3BroadcastHelper.sendFailedBroadcast(this, code);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //+ by Ricardo 09/15 ,fix camera exception release SoundPool
        if (soundUtils != null)
            soundUtils.release();
        soundUtils = null;
        //- by Ricardo 09/15 ,fix camera exception
        // 如果不是L3调用的话，退出取消屏幕独占
        if (Params.sL3Params == null) {
            UIUtils.screenMonopoly(-1);
        }
        if (mAutoFocusHandler != null) {
            mAutoFocusHandler.removeCallbacksAndMessages(null);
            mAutoFocusHandler = null;
        }
    }

    private void initScanConfig() {
        // 是否开启同一幅图一次解多个条码,0表示只解一个，1为多个
        mImageScanner.setConfig(0, Config.ENABLE_MULTILESYMS, 0);
        // 是否开启识别反色二维码,0表示不识别，1为识别
        mImageScanner.setConfig(0, Config.ENABLE_INVERSE, 1);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        try {
            mCamera = Camera.open();
        } catch (Exception e) {
            mCamera = null;
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        AsyncTask.execute(new Runnable() {

            @Override
            public void run() {
                if (mHolder.getSurface() == null) {
                    return;
                }
                try {
                    mCamera.stopPreview();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                try {
                    setCameraParameters();
                    mCamera.setDisplayOrientation(90); // 竖屏显示
                    mCamera.setPreviewDisplay(mHolder);
                    mCamera.setPreviewCallback(previewCallback);
                    mCamera.startPreview();
                    mCamera.autoFocus(autoFocusCallback);
                } catch (Exception e) {
                    LogUtil.e("DBG", "Error starting camera preview: " + e.getMessage());
                }

            }

        });
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            mCamera.setPreviewCallback(null);
            mCamera.release();
            mCamera = null;
        }
    }

    // 获取最佳的屏幕显示尺寸
    private Point getBestCameraResolution(Camera.Parameters parameters, Point screenResolution) {
        float tmp;
        float minDiff = 100f;
        float x_d_y = (float) screenResolution.x / (float) screenResolution.y;
        Camera.Size best = null;
        List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
        for (Camera.Size s : supportedPreviewSizes) {
            tmp = Math.abs(((float) s.height / (float) s.width) - x_d_y);
            if (tmp < minDiff) {
                minDiff = tmp;
                best = s;
            }
        }
        return new Point(best.width, best.height);
    }

    private void setCameraParameters() {
        if (mCamera == null) return;
        // 摄像头预览分辨率设置和图像放大参数设置，非必须，根据实际解码效果可取舍
        Camera.Parameters parameters = mCamera.getParameters();
        WindowManager manager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
        Display display = manager.getDefaultDisplay();
        ScanConfig.BEST_RESOLUTION = getBestCameraResolution(parameters, new Point(display.getWidth(), display.getHeight()));
        parameters.setPreviewSize(ScanConfig.BEST_RESOLUTION.x, ScanConfig.BEST_RESOLUTION.y);
        parameters.set("orientation", "portrait");
        // parameters.set("zoom", String.valueOf(27 / 10.0)); // 放大图像2.7倍
        mCamera.setParameters(parameters);
    }

    /**
     * 预览数据
     */
    private Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() {

        public void onPreviewFrame(byte[] data, Camera camera) {
            if (isRUN.compareAndSet(false, true)) {
                //+ by Ricardo 09/15 ,fix camera exception getParameters maybe exception
                try {
                    Camera.Parameters parameters = camera.getParameters();
                    Camera.Size size = parameters.getPreviewSize(); // 获取预览分辨率
                    // 创建解码图像，并转换为原始灰度数据，注意图片是被旋转了90度
                    execPreviewData(data, size.width, size.height);
                } catch (Exception e) {
                    e.printStackTrace();
                    execPreviewData(data, ScanConfig.BEST_RESOLUTION.x, ScanConfig.BEST_RESOLUTION.y);
                }
                //2 by Ricardo 09/15 ,fix camera exception
            }
        }

    };

    //+ by Ricardo 09/15 ,fix camera exception
    private void execPreviewData(byte[] data, int width, int height) {
        Image source = new Image(width, height, "Y800");
        Rect scanImageRect = mFinderView.getScanImageRect(height, width);
        // 图片旋转了90度，将扫描框的TOP作为left裁剪
        source.setCrop(scanImageRect.top, scanImageRect.left, scanImageRect.height(), scanImageRect.width());
        source.setData(data); // 填充数据
        AsyncDecode asyncDecode = new AsyncDecode();
        asyncDecode.execute(source); // 调用异步执行解码
    }

    //- by Ricardo 09/15 ,fix camera exception
    public class AsyncDecode extends AsyncTask<Image, Void, List<Map<String, String>>> {

        @Override
        protected List<Map<String, String>> doInBackground(Image... params) {
            List<Map<String, String>> result = new ArrayList<>();
            Image src_data = params[0]; // 获取灰度数据
            // 解码，返回值为0代表失败，>0表示成功
            int data = mImageScanner.scanImage(src_data);
            if (data != 0) {
                playBeepSoundAndVibrate(); // 解码成功播放提示音
                SymbolSet symbols = mImageScanner.getResults(); // 获取解码结果
                for (Symbol sym : symbols) {
                    HashMap<String, String> temp = new HashMap<>();
                    temp.put(ScanConfig.TYPE, sym.getSymbolName());
                    temp.put(ScanConfig.VALUE, sym.getResult());
                    result.add(temp);
                    break;
                }
            }
            return result;
        }

        @Override
        protected void onPostExecute(List<Map<String, String>> result) {
            super.onPostExecute(result);
            if (!result.isEmpty()) {
                Map<String, String> map = result.get(0);
                String codeValue = map.get(ScanConfig.VALUE);
                if (isValidQrCode(codeValue)) {//如果判断出这是一个正确的二维码，则才停止扫描新的二维码,否则将继续扫描
                    onScanSuccess(codeValue);
                    return;
                }
            }
            isRUN.set(false);
        }
    }

    protected boolean isValidQrCode(String codeValue) {
        return true;
    }

    protected abstract void onScanSuccess(String codeValue);

    /**
     * 自动对焦回调
     */
    private Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {

        @Override
        public void onAutoFocus(boolean success, Camera camera) {
            if (mAutoFocusHandler != null) {
                mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
            }
        }

    };

    // 自动对焦
    private Runnable doAutoFocus = new Runnable() {

        @Override
        public void run() {
            if (null == mCamera || null == autoFocusCallback) {
                return;
            }
            //+ by Ricardo 09/15 ,fix camera exception autoFocus maybe exception
            try {
                mCamera.autoFocus(autoFocusCallback);
            } catch (Exception e) {
                e.printStackTrace();
                if (mAutoFocusHandler != null) {
                    mAutoFocusHandler.postDelayed(doAutoFocus, 1000);
                }
            }
            //- by Ricardo 09/15 ,fix camera exception
        }

    };

    private void initBeepSound() {
        if (soundUtils == null) {
            soundUtils = new SoundUtils(this, SoundUtils.RING_SOUND);
            soundUtils.putSound(0, R.raw.beep);
        }
    }

    private void playBeepSoundAndVibrate() {
        if (soundUtils != null) {
            soundUtils.playSound(0, SoundUtils.SINGLE_PLAY);
        }
    }

}
